/*
    MarsEngine Shader

	Author: cherlix

    Directional Light Shader for 3D Objects
*/

Texture2D diffuseMap : register( t0 );
SamplerState diffuseSampler : register( s0 );

struct DirectionalLight
{
	float4 Ambient;
	float4 Diffuse;
	float4 Specular;
	float3 Direction;
	float  Pad;
};

struct Material
{
	float4 Ambient;
	float4 Diffuse;
	float4 Specular; // w = SpecPower
	float4 Reflect;
};

cbuffer cbPerFrame
{
	DirectionalLight directionalLight;
	float4 eyePosW;
};

cbuffer cbPerObjectVS
{
	matrix worldMatrix;
	matrix worldInvTransposeMatrix;
	matrix worldViewProjMatrix;
};

cbuffer cbPerObjectPS
{
	Material material;
};

struct VS_Input
{
    float3 pos     : POSITION;
    float2 tex0	   : TEXCOORD0;
	float3 normal  : NORMAL;
};

struct PS_Input
{
	float4 posH    : SV_POSITION;
    float2 tex0    : TEXCOORD0;
    float3 posW    : POSITION;
    float3 normalW : NORMAL;
};

void ComputeDirectionalLight( Material mat, 
							  DirectionalLight light, 
                              float3 normal, 
							  float3 toEye,
					          out float4 ambient,
						      out float4 diffuse,
						      out float4 spec)
{
	// Initialize outputs.
	ambient = float4(0.0f, 0.0f, 0.0f, 0.0f);
	diffuse = float4(0.0f, 0.0f, 0.0f, 0.0f);
	spec    = float4(0.0f, 0.0f, 0.0f, 0.0f);

	// The light vector aims opposite the direction the light rays travel.
	float3 lightVec = -light.Direction;

	// Add ambient term.
	ambient = mat.Ambient * light.Ambient;	

	// Add diffuse and specular term, provided the surface is in 
	// the line of site of the light.
	
	float diffuseFactor = dot( lightVec, normal );

	// Flatten to avoid dynamic branching.
	[flatten]
	if ( diffuseFactor > 0.0f )
	{
		float3 v         = reflect( -lightVec, normal );
		float specFactor = pow( max( dot( v, toEye ), 0.0f ), mat.Specular.w );
					
		diffuse = diffuseFactor * mat.Diffuse * light.Diffuse;
		spec    = specFactor * mat.Specular * light.Specular;
	}
}

PS_Input VS_Main( VS_Input vertex )
{
    PS_Input vsOut = ( PS_Input )0;
    vsOut.posW = mul( float4( vertex.pos, 1.0f ), worldMatrix ).xyz;
    vsOut.posH = mul( float4( vertex.pos, 1.0f ), worldViewProjMatrix );
	vsOut.normalW = mul( vertex.normal, worldInvTransposeMatrix );
    vsOut.tex0 = vertex.tex0;

    return vsOut;
}

float4 PS_Main( PS_Input frag ) : SV_TARGET
{
	frag.normalW = normalize( frag.normalW );
	float3 toEyeW = normalize( eyePosW.xyz - frag.posW );

	// Start with a sum of zero. 
	float4 ambient = float4( 0.0f, 0.0f, 0.0f, 0.0f );
	float4 diffuse = float4( 0.0f, 0.0f, 0.0f, 0.0f );
	float4 spec    = float4( 0.0f, 0.0f, 0.0f, 0.0f );

	// Sum the light contribution from each light source.
	float4 A, D, S;

	ComputeDirectionalLight(material, directionalLight, frag.normalW, toEyeW, A, D, S);
	ambient += A;  
	diffuse += D;
	spec    += S;
	
	float4 litColor = ambient + diffuse + spec;
	float4 texColor = diffuseMap.Sample( diffuseSampler, frag.tex0 );
	litColor.a = material.Diffuse.a + texColor.a;
    return litColor + texColor; //colorMap_.Sample( colorSampler_, frag.tex0 );
	//return float4( 1.0f, 1.0f, 1.0f, 1.0f );
}